from certificate_manager.models import *
from certificate_manager.serializers import DepartmentSerializer, UserSerializer, CertSerializer
from django.test import tag
from rest_framework import status
from rest_framework.renderers import JSONRenderer
from rest_framework.test import APITestCase, force_authenticate
import datetime

@tag('test_cert')
class TestCert(APITestCase):
        '''
        在这里实现证书的相关操作：增加、修改（批准、修改申请中的内容）、查询（关键是没有被批准的不能上）        
        '''
        def setUp(self):
                department = self.department = Department.objects.create(name='test_department')
                department.save()

                # 添加用户

                User.objects.create_user(uid='1813004316', name='yves', password='123', department=department)
                User.objects.create_user(uid='lizhong', name='lizhong', password='123', department=department)

                # 添加一个竞赛类目
                cate = Cate.objects.create(name='测试竞赛-PAT认证')
                cate.save()
                # 添加一个限制条件
                DepartRestrict.objects.create(cate=cate, department=department, people_limit_min=1, people_limit_max=2).save()
                CollectCate.objects.create(cate=Cate.objects.get(name='测试竞赛-PAT认证')).save()
                
        def test_add_cert(self):
                url = '/certs/'
                # 在添加的过程中应该默认添加当前用户
                data = {
                        'cate': 1,
                        'score': '100', # 成绩类的是否应该设置总成绩
                        'achieved_date': '2020-01-01',
                        'join_list': [ # 第一个人必须是申请人 需要参数检查
                                { 'restrict': 1, 'uid': '1813004316', 'play_role_imp': 50}, # 这里显示的部门为了方便看责任人
                                { 'restrict': 1, 'uid': 'lizhong', 'play_role_imp': 50}
                        ],
                        'pics': [
                            { 'name': '123' }
                        ]
                }
                response = self.client.post(url, data, format='json')

                # 未登陆时

                self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

                # 登陆后
                self.client.login(uid='1813004316', password='123')
                response = self.client.post(url, data, format='json')
                print(response.data)
                self.assertEqual(response.status_code, status.HTTP_201_CREATED)
                

                self.assertEqual(Cert.objects.count(), 1)

                check_cert = Cert.objects.get(pk=1)
                self.assertEqual(check_cert.score, '100')
                self.assertEqual(check_cert.achieved_date, datetime.date(2020, 1, 1))
                
                # 下面检查Join关系是否正常
                join_set = check_cert.join_set.all()
                self.assertEqual(join_set.count(), 2)
                self.assertEqual(join_set[0].user.uid, '1813004316')
                self.assertEqual(join_set[1].user.uid, 'lizhong')

                # 下面检查图片是否添加进去了
                self.assertEqual(check_cert.certpic_set.count(), 1)
                self.assertEqual(check_cert.certpic_set.get().name, '123')

        def test_add_bad_cert_not_group(self):
                cate = Cate.objects.create(name='测试竞赛', collect_part=Cate.SCORE)
                cate.save()

                DepartRestrict.objects.create(cate=cate, department=Department.objects.get(name='test_department'), people_limit_min=1, people_limit_max=1).save()

                ccate = CollectCate.objects.create(cate=cate)
                ccate.save()

                url = '/certs/'
                data = {
                        'cate': ccate.pk,
                        'score': '100',
                        'achieved_date': '2020-01-01',
                        'join_list': [
                                { 'department': 1, 'uid': '1813004316', 'play_role_imp': 50}, # 这里显示的部门为了方便看责任人
                                { 'department': 1, 'uid': 'lizhong', 'play_role_imp': 50}
                        ]
                }
                self.client.login(uid='1813004316', password='123')
                response = self.client.post(url, data, format='json')
                self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
                
        def test_bad_add_other_cert(self):
                '''
                检查第一个用户是不是当前登陆的用户，如果不是说明在做API测试
                '''
                pass

        def test_cert_join_list_acceptable(self):
                '''
                检查用户列表是否合法（有队员，有审查人）
                '''
                pass

        def test_get_index_cert_list(self):
                self.create_cert(cate='cert1', people=['1', '2', '3'])
                self.create_cert(cate='cert2', people=['4', '5', '6'])
                
                url = '/certs/'
                response = self.client.get(url)
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                cert_json_list = response.data
                # 我们要在这里检查结果，应该都显示不出来才行(因为没有批准)
                self.assertEqual(len(cert_json_list), 0)
                pass

        def test_auth_get_my_cert_list(self):
                self.create_cert(cate='cert1', people=['1', '2', '3'])
                self.create_cert(cate='cert2', people=['4', '5', '6'])
                
                result = self.client.login(uid='1', password='123')
                # 检查是否登陆成功
                self.assertEqual(result, True)

                url = '/certs/'
                data = { "all_accept": False }

                response = self.client.get(url, data, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)              
                back_cert_list = response.data
                self.assertEqual(len(back_cert_list), 1)

        def test_all_accept_cert(self):
                self.create_cert(cate='cert1', people=['1', '2', '3'])
                
                cert = Cert.objects.get(pk=1)

                url = f'/certs/{cert.pk}/join/'
                data = {
                        'approve': True,
                        'msg': ''
                }
                
                for join in cert.join_set.all():
                        user = join.user
                        logined = self.client.login(uid=user.uid, password='123')
                        self.assertEqual(logined, True)

                        response = self.client.post(url, data, format='json')
                        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
                        # 下面检查是否正确
                        user_join = user.join_set.get(cert=cert)
                        self.assertEqual(user_join.status, Join.ACCEPT)

                del cert.all_accept
                self.assertEqual(cert.all_accept, True)

                # 尝试再次同意
                # 首先是未登陆状态
                self.client.logout()
                response = self.client.post(url, data, format='json')
                self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

                # 接下来尝试重复提交
                data = {
                        'approve': False,
                        'msg': ''
                }
                self.client.login(uid='1', password='123')
                response = self.client.post(url, data, format='json')
                self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        
        def create_cert(self, cate='蓝桥杯', people=[], pazz=[], reject=[]):
                # 里面涉及到的所有字段如果不存在就自动创建
                try:
                        cate = Cate.objects.get(name=cate)
                except Cate.DoesNotExist:
                        cate = Cate.objects.create(name=cate)
                        # 这里需要添加一个默认限制
                        restrict = DepartRestrict.objects.create(cate=cate, department=self.department, restrict_type=DepartRestrict.JOINER, people_limit_max=len(people))
                        restrict.save()

                        cate.save()
                
                try:
                        ccate = cate.collectcate_set.get(pk=1)
                except CollectCate.DoesNotExist:
                        ccate = CollectCate.objects.create(cate=cate)

                # 下面可以创建证书了
                cert = Cert.objects.create(cate=ccate, achieved_date='2020-01-01')
                cert.save()

                # 下面创建用户join
                for uid in people:
                        try:
                                user = User.objects.get(uid=uid)
                        except User.DoesNotExist:
                                user = User.objects.create_user(
                                        uid=uid,
                                        name=uid, 
                                        department=self.department, 
                                        password='123'
                                )
                        # 这里我们要解决添加用户时候需要指定是哪个restrict
                        join = Join.objects.create(cert=cert, restrict=restrict, user=user)

                        if uid in pazz:
                                join.status = Join.ACCEPT
                        elif uid in reject:
                                join.status = Join.REJECT
                                join.msg = f'{uid} rejected'
                        join.save()

                if len(pazz) == len(people):
                        cert.all_accept = True
                        cert.save()
                return cert
                
        def test_get_cert(self):
                cert = self.create_cert(cate='cert1', people=['1', '2', '3'], pazz=['1', '2', '3'])
                # 如果是一个全部通过的证书，那么可以访问
                url = f'/certs/{cert.pk}/'
                response = self.client.get(url) 
                self.assertEqual(cert.all_accept, True)
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data, CertSerializer(cert).data)

        def test_get_cert_unauth(self):
                # 如果是一个部分或没有被通过的证书，那么在未登陆的状态、其他人都不应该获得其信息，只有登陆的并且是和证书相关的用户才能获得其信息
                cert = self.create_cert(cate='cert1', people=['4', '5'], pazz=['4'])
                url = f'/certs/{cert.pk}/'
                ## 现在是未登陆状态，应当出错
                response = self.client.get(url) 
                self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

        def test_get_cert_auth(self):
                cert = self.create_cert(cate='cert1', people=['4', '5'], pazz=['4'])
                url = f'/certs/{cert.pk}/'

                ## 现在是登陆状态，应当返回
                logined = self.client.login(uid='4', password='123')
                self.assertEqual(logined, True)

                response = self.client.get(url) 
                self.assertEqual(response.status_code, status.HTTP_200_OK)

        def test_update_cert(self):
                cert = self.create_cert(cate='cert1', people=['4', '5'], pazz=['4'])
                url = '/certs/1/'
                data = {}
                response = self.client.patch(url, data, format='json')
                # 未登陆状态不能修改
                self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
                
                # 即使是登陆的用户，也不能修改
                self.client.login(uid='4', password='123')
                response = self.client.patch(url, data, format='json')
                self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

        def test_build_team(self):
                # 待实现：我们需要检查用户添加的列表是否合法
                pass

        def test_delete_cert(self):
                # 任何用户都不能删除cert
                cert = self.create_cert(cate='cert1', people=['4', '5'], pazz=['4'])
                url = '/certs/1/'
                
                self.client.login(uid='4', password='123')
                response = self.client.delete(url)
                self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

        def test_accept_outof_date(self):
                cert = self.create_cert(cate='cert1', people=['4', '5'], pazz=['4'])
                ccate = cert.cate
                ccate.start_date = datetime.date(2000, 1, 1)
                ccate.end_date = datetime.date(2000, 1, 4)
                ccate.save()
                
                # 现在时间修改完毕 我们模拟同意
                url = f'/certs/{cert.pk}/join/'
                data = {
                        'approve': True,
                        'msg': ''
                }
                self.client.login(uid='5', password='123')
                response = self.client.post(url, data, format='json')
                print(response.data)    

        @tag('test_add_cert_score')
        def test_add_cert_score(self):
            # 我们需要准备数据 先从创建cate开始
            cate = Cate.objects.create(
                name='成绩类竞赛',
                collect_part=Cate.SCORE
            )
            cate.save()

            # 创建部门，我们分开做吧
            dep_joiner = Department.objects.create(
                name='软件学院'
            )
            dep_joiner.save()

            # 添加学生
            student = User.objects.create_user(uid='joiner_1', name='yves', password='123', department=dep_joiner)
            student.save()

            # 添加两个限制
            restrict_joiner = DepartRestrict.objects.create(
                cate=cate,
                department=dep_joiner
            )
            restrict_joiner.save()

            ccate = CollectCate.objects.create(
                cate=cate
            )
            ccate.save()

            self.client.login(uid='joiner_1', password='123')
            # 创建部门，我们分开做吧
            dep_advisor = Department.objects.create(
                name='中北大学'
            )
            dep_advisor.save()

            # 添加学生
            teacher = User.objects.create_user(uid='t1', name='t1', password='123', department=dep_advisor)
            teacher.save()

            # 添加两个限制
            restrict_advisor = DepartRestrict.objects.create(
                cate=cate,
                department=dep_advisor
            )
            restrict_advisor.save()
            
            data = {
                'achieved_date': "2022-02-01",
                'cate': ccate.pk,
                'join_list': [
                    {
                        'play_role_imp': "100",
                        'restrict': restrict_joiner.pk,
                        'uid': student.uid
                    },
                    {
                        'play_role_imp': 0,
                        'restrict': restrict_advisor.pk,
                        'uid': "t1"
                    }
                ],
                'level': None,
                'name': 0,
                'pics': [
                    {
                        "name": "GEEXIN_1645102645981"
                    }
                ],
                'score': "100"
            }
            url = '/certs/'


            response = self.client.post(url, data, format='json')

            print(response.data)
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)

            # 下面要测试必须能够得到这个没有批准的证书
            url = '/certs/?all_accept=False'
            response = self.client.get(url, format='json')
            print(response.data)
